#include "Common.h"

TerrainHandler::TerrainHandler(ui32 mapid) : map(mapid), m_mapfile(NULL), m_cellsloaded(false)
{
}

bool TerrainHandler::LoadMapFile()
{
	char path[255];
	sprintf(path, "maps\\Map_%u.bin", map);
	m_mapfile = fopen(path, "rb");
	if(!m_mapfile)
	{
		//Log->Error("Terrain", "Could not find file 'Map_%u.bin' in map-folder!", map);
		return false;
	}
	fseek(m_mapfile, 0, SEEK_END);
	long sz = ftell(m_mapfile);
	fseek(m_mapfile, 0, SEEK_SET);
	if(sz < (512 * 512 * 4))
	{
		Log->Error("Terrain", "File 'Map_%u.bin' has incorrect headersize!", map);
		return false;
	}
	fread(CellOffset, 512 * 512 * 4, 1, m_mapfile);
	m_cellinfo = new CellInformation**[8 * 64];
	for(ui32 i = 0; i < (8 * 64); ++i)
	{
		m_cellinfo[i] = new CellInformation*[8 * 64];
		for(ui32 a = 0; a < (8 * 64); ++a)
			m_cellinfo[i][a] = 0;
	}
	m_lastaccess = new DWORD*[8 * 64];
	for(ui32 i = 0; i < (8 * 64); ++i)
	{
		m_lastaccess[i] = new DWORD[8 * 64];
		for(ui32 a = 0; a < (8 * 64); ++a)
			m_lastaccess[i][a] = GetTickCount();
	}
	Log->Success("Terrain", "Loaded mapfile 'Map_%u.bin'!", map);
	m_cellsloaded = true;
	return true;
}

float TerrainHandler::GetLandHeight(float x, float y)
{
	if(!m_mapfile)
		return NO_COORD_RESULT;
	if(x > MAX_X || x < MIN_X || y > MAX_Y || y < MIN_Y)
		return NO_COORD_RESULT;
	ui32 cellX = ui32(((MAX_X - x) / CELL_SIZE));
	ui32 cellY = ui32(((MAX_Y - y) / CELL_SIZE));
	CellInformation* cinfo = GetCellInfo(cellX, cellY);
	if(!cinfo)
		return NO_COORD_RESULT;
	ui32 tmpx = (ui32)(MAX_X - x);
	ui32 tmpy = (ui32)(MAX_Y - y);
	tmpx -= (ui32)(cellX * CELL_SIZE);
	tmpy -= (ui32)(cellY * CELL_SIZE);
	float tx = tmpx * (256 / 8 / CELL_SIZE);
	ui32 xoffset = ui32(tx);
	if(tx - (xoffset * CELL_SIZE) <= 0.5f)
		++xoffset;
	float ty = tmpy * (256 / 8 / CELL_SIZE);
	ui32 yoffset = ui32(ty);
	if(ty - (yoffset * CELL_SIZE) <= 0.5f)
		++yoffset;
	if(xoffset > 31)
		xoffset = 31;
	if(yoffset > 31)
		yoffset = 31;
	return cinfo->Z[xoffset][yoffset];
}

ui16 TerrainHandler::GetAreaId(float x, float y)
{
	if(!m_mapfile)
		return NO_AREA_RESULT;
	if(x > MAX_X || x < MIN_X || y > MAX_Y || y < MIN_Y)
		return NO_AREA_RESULT;
	ui32 cellX = ui32(((MAX_X - x) / CELL_SIZE));
	ui32 cellY = ui32(((MAX_Y - y) / CELL_SIZE));
	CellInformation* cinfo = GetCellInfo(cellX, cellY);
	if(!cinfo)
		return NO_AREA_RESULT;
	ui32 tmpx = (ui32)(MAX_X - x);
	ui32 tmpy = (ui32)(MAX_Y - y);
	tmpx -= (ui32)(cellX * CELL_SIZE);
	tmpy -= (ui32)(cellY * CELL_SIZE);
	return cinfo->AreaID[ui32((tmpx * (16 / 8 / CELL_SIZE)))][ui32((tmpy * (16 / 8 / CELL_SIZE)))];
}

CellInformation* TerrainHandler::GetCellInfo(ui32 x, ui32 y)
{
	if(x > 511 || y > 511)
		return NULL;
	CellInformation* info = m_cellinfo[x][y];
	if(!info)
	{
		LoadCell(x, y);
		info = m_cellinfo[x][y];
	}
	m_lastaccess[x][y] = GetTickCount();
	return info;
}

void TerrainHandler::LoadCell(ui32 x, ui32 y)
{
	ScopedLock<Mutex> l(m_filemutex);
	ui32 offset = CellOffset[x][y];
	fseek(m_mapfile, 0, SEEK_END);
	ui32 sz = ftell(m_mapfile);
	fseek(m_mapfile, 0, SEEK_SET);
	if(offset > sz)
		return;
	fseek(m_mapfile, offset, SEEK_SET);
	m_cellinfo[x][y] = new CellInformation;
	fread(m_cellinfo[x][y], sizeof(CellInformation), 1, m_mapfile);
}

void TerrainHandler::Update()
{
	if(!m_cellsloaded)
		return;
	m_filemutex.Acquire();
	DWORD tim = GetTickCount();
	for(ui32 i = 0; i < (8 * 64); ++i)
		for(ui32 a = 0; a < (8 * 64); ++a)
			if(tim - m_lastaccess[i][a] > 1000 && m_cellinfo[i][a])
			{
				delete m_cellinfo[i][a];
				m_cellinfo[i][a] = 0;
			}
	m_filemutex.Release();

}